/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package GA;

import java.util.Random;

/**
 *
 * @author S094182
 */
public class Population {
    BinaryGenome population[];
    IEnvironment enviroment;
    Random rand = new Random(System.currentTimeMillis());
    BinaryGenome best;
    BinaryGenome generationBest;
    double prevAvgFitness = 0;
    public BinaryGenome getOverallBest() { return best; }
    
    public Population(IEnvironment enviroment, int size)
    {
        this.enviroment = enviroment;
        population = new BinaryGenome[size];
        for (int i = 0; i < population.length; i++) {
            population[i] = new BinaryGenome(enviroment.getGeneLength(), enviroment.getFitnessType());            
        }
        best = population[0];
    }
    
    private void ratePopulation() 
    {
        generationBest = null;
        for (int i = 0; i < population.length; i++) {
            enviroment.evaluateGenome(population[i]);
            if (population[i].isFitter(best)) {
                best = population[i];
            }
            if (generationBest == null || population[i].isFitter(generationBest)) {
                generationBest = population[i];
            }
        }
        prevAvgFitness = calcAvgFitness();
    }
    
    private double calcAvgFitness(){
        double avg = 0;
        for (int i = 0; i < population.length; i++) {
            avg += (population[i].getFitness() / population.length);
        }
        return avg;
    }
    
    public double avgFitness(){
        return prevAvgFitness;
    }
    
    public BinaryGenome getGenerationBest(){
        return generationBest;
    }
    
    public BinaryGenome[] getPopulation(){
        return population;
    }
    
    public void evolvePopulation() 
    {
        BinaryGenome[] nextGen = new BinaryGenome[population.length];
        
        int childN = 0;
        ratePopulation();
        
        while(childN < population.length) {
            int r = rand.nextInt(1000);
            
            if (r < 50) {
                nextGen[childN++] = tourN(5);
            } else if (r >= 50 && r < 990) {
                BinaryGenome[] xc = BinaryGenome.onePointX(tourN(4), tourN(4));
                nextGen[childN++] = xc[0];
                if (childN < population.length)
                    nextGen[childN++] = xc[1];
            } else {
                nextGen[childN++] = BinaryGenome.mutateLocus(tourN(3));
            }
        }
        population = nextGen;
    }
    
    public BinaryGenome tourN(int n)
    {
        BinaryGenome winner = population[rand.nextInt(population.length)];
        int r;
        for (int i = 0; i < n-1; i++) {
            r = rand.nextInt(population.length);
            if (population[r].isFitter(winner))
                winner = population[r];
        }
        return winner;
    }
}
